<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Vue 数据响应式 | Guru Note</title>
    <meta name="generator" content="VuePress 1.7.1">
    <link rel="stylesheet" href="./font/index.css">
    <script src="/docs/icon/svg.js"></script>
    <meta name="description" content="Sea of dawn">
    
    <link rel="preload" href="/docs/assets/css/0.styles.efa081cd.css" as="style"><link rel="preload" href="/docs/assets/js/app.cdec4db9.js" as="script"><link rel="preload" href="/docs/assets/js/2.993bd611.js" as="script"><link rel="preload" href="/docs/assets/js/119.cbb17c5e.js" as="script"><link rel="preload" href="/docs/assets/js/7.5a12abef.js" as="script"><link rel="prefetch" href="/docs/assets/js/10.c3177bdb.js"><link rel="prefetch" href="/docs/assets/js/100.60c23478.js"><link rel="prefetch" href="/docs/assets/js/101.7ea29e1b.js"><link rel="prefetch" href="/docs/assets/js/102.7f47e485.js"><link rel="prefetch" href="/docs/assets/js/103.ea9ce400.js"><link rel="prefetch" href="/docs/assets/js/104.4ec6a518.js"><link rel="prefetch" href="/docs/assets/js/105.75526347.js"><link rel="prefetch" href="/docs/assets/js/106.01f6b03b.js"><link rel="prefetch" href="/docs/assets/js/107.69fe0811.js"><link rel="prefetch" href="/docs/assets/js/108.fa23768b.js"><link rel="prefetch" href="/docs/assets/js/109.90df1698.js"><link rel="prefetch" href="/docs/assets/js/11.54347528.js"><link rel="prefetch" href="/docs/assets/js/110.dd8d7227.js"><link rel="prefetch" href="/docs/assets/js/111.ccf25ceb.js"><link rel="prefetch" href="/docs/assets/js/112.6963298f.js"><link rel="prefetch" href="/docs/assets/js/113.30ceb3d8.js"><link rel="prefetch" href="/docs/assets/js/114.42ef6603.js"><link rel="prefetch" href="/docs/assets/js/115.f1db7817.js"><link rel="prefetch" href="/docs/assets/js/116.92971223.js"><link rel="prefetch" href="/docs/assets/js/117.c5a65e7e.js"><link rel="prefetch" href="/docs/assets/js/118.e329035d.js"><link rel="prefetch" href="/docs/assets/js/12.c8144ee8.js"><link rel="prefetch" href="/docs/assets/js/120.8537f6a6.js"><link rel="prefetch" href="/docs/assets/js/121.257d3851.js"><link rel="prefetch" href="/docs/assets/js/122.96a5f921.js"><link rel="prefetch" href="/docs/assets/js/123.2220fd12.js"><link rel="prefetch" href="/docs/assets/js/124.552b1a29.js"><link rel="prefetch" href="/docs/assets/js/125.4e36fe37.js"><link rel="prefetch" href="/docs/assets/js/126.3939cdcc.js"><link rel="prefetch" href="/docs/assets/js/127.014df434.js"><link rel="prefetch" href="/docs/assets/js/13.edc237a8.js"><link rel="prefetch" href="/docs/assets/js/14.66270d4f.js"><link rel="prefetch" href="/docs/assets/js/15.0804164b.js"><link rel="prefetch" href="/docs/assets/js/16.dec928ab.js"><link rel="prefetch" href="/docs/assets/js/17.bbfc90a8.js"><link rel="prefetch" href="/docs/assets/js/18.76904860.js"><link rel="prefetch" href="/docs/assets/js/19.80a98011.js"><link rel="prefetch" href="/docs/assets/js/20.c39e42bd.js"><link rel="prefetch" href="/docs/assets/js/21.287b744a.js"><link rel="prefetch" href="/docs/assets/js/22.c9506be7.js"><link rel="prefetch" href="/docs/assets/js/23.9732a229.js"><link rel="prefetch" href="/docs/assets/js/24.21ed1f05.js"><link rel="prefetch" href="/docs/assets/js/25.8f1926f6.js"><link rel="prefetch" href="/docs/assets/js/26.61b6eb9f.js"><link rel="prefetch" href="/docs/assets/js/27.3706753c.js"><link rel="prefetch" href="/docs/assets/js/28.b6b182cf.js"><link rel="prefetch" href="/docs/assets/js/29.ae979ad9.js"><link rel="prefetch" href="/docs/assets/js/3.a7f8dd77.js"><link rel="prefetch" href="/docs/assets/js/30.f2233269.js"><link rel="prefetch" href="/docs/assets/js/31.06780314.js"><link rel="prefetch" href="/docs/assets/js/32.2dad91d1.js"><link rel="prefetch" href="/docs/assets/js/33.87ec6e22.js"><link rel="prefetch" href="/docs/assets/js/34.7b75f220.js"><link rel="prefetch" href="/docs/assets/js/35.3184991f.js"><link rel="prefetch" href="/docs/assets/js/36.28248fbe.js"><link rel="prefetch" href="/docs/assets/js/37.5824a979.js"><link rel="prefetch" href="/docs/assets/js/38.99a364fe.js"><link rel="prefetch" href="/docs/assets/js/39.a5f43732.js"><link rel="prefetch" href="/docs/assets/js/4.a55d89ed.js"><link rel="prefetch" href="/docs/assets/js/40.629f78f7.js"><link rel="prefetch" href="/docs/assets/js/41.e4f58d1c.js"><link rel="prefetch" href="/docs/assets/js/42.9f41aa47.js"><link rel="prefetch" href="/docs/assets/js/43.636412b6.js"><link rel="prefetch" href="/docs/assets/js/44.3b491aef.js"><link rel="prefetch" href="/docs/assets/js/45.77df19bc.js"><link rel="prefetch" href="/docs/assets/js/46.01f53ddd.js"><link rel="prefetch" href="/docs/assets/js/47.476e85c9.js"><link rel="prefetch" href="/docs/assets/js/48.198502dc.js"><link rel="prefetch" href="/docs/assets/js/49.0d59d332.js"><link rel="prefetch" href="/docs/assets/js/5.1597c0f8.js"><link rel="prefetch" href="/docs/assets/js/50.02baf101.js"><link rel="prefetch" href="/docs/assets/js/51.c9fbd54d.js"><link rel="prefetch" href="/docs/assets/js/52.4cb4459b.js"><link rel="prefetch" href="/docs/assets/js/53.248450d7.js"><link rel="prefetch" href="/docs/assets/js/54.83f12d1e.js"><link rel="prefetch" href="/docs/assets/js/55.b18accba.js"><link rel="prefetch" href="/docs/assets/js/56.8a160b09.js"><link rel="prefetch" href="/docs/assets/js/57.b854a940.js"><link rel="prefetch" href="/docs/assets/js/58.4500f315.js"><link rel="prefetch" href="/docs/assets/js/59.59400e36.js"><link rel="prefetch" href="/docs/assets/js/6.887ba020.js"><link rel="prefetch" href="/docs/assets/js/60.4dd5b5bb.js"><link rel="prefetch" href="/docs/assets/js/61.50d8c8f6.js"><link rel="prefetch" href="/docs/assets/js/62.17d10daa.js"><link rel="prefetch" href="/docs/assets/js/63.d5f821cc.js"><link rel="prefetch" href="/docs/assets/js/64.7bf2519f.js"><link rel="prefetch" href="/docs/assets/js/65.0a1c9bc8.js"><link rel="prefetch" href="/docs/assets/js/66.1bcaa81c.js"><link rel="prefetch" href="/docs/assets/js/67.326bdf9b.js"><link rel="prefetch" href="/docs/assets/js/68.2b3b63b2.js"><link rel="prefetch" href="/docs/assets/js/69.c9b1a1a9.js"><link rel="prefetch" href="/docs/assets/js/70.a5fede78.js"><link rel="prefetch" href="/docs/assets/js/71.288d9643.js"><link rel="prefetch" href="/docs/assets/js/72.8665d6b8.js"><link rel="prefetch" href="/docs/assets/js/73.47155429.js"><link rel="prefetch" href="/docs/assets/js/74.4d4738f8.js"><link rel="prefetch" href="/docs/assets/js/75.659a325f.js"><link rel="prefetch" href="/docs/assets/js/76.a263f692.js"><link rel="prefetch" href="/docs/assets/js/77.9d86d59e.js"><link rel="prefetch" href="/docs/assets/js/78.a41b5d88.js"><link rel="prefetch" href="/docs/assets/js/79.5d0fc4cc.js"><link rel="prefetch" href="/docs/assets/js/8.80d0c81d.js"><link rel="prefetch" href="/docs/assets/js/80.01a11f6a.js"><link rel="prefetch" href="/docs/assets/js/81.9c0207d9.js"><link rel="prefetch" href="/docs/assets/js/82.12be8e04.js"><link rel="prefetch" href="/docs/assets/js/83.00fa5f46.js"><link rel="prefetch" href="/docs/assets/js/84.f14cd53c.js"><link rel="prefetch" href="/docs/assets/js/85.e9d7c0d1.js"><link rel="prefetch" href="/docs/assets/js/86.eb78fbbf.js"><link rel="prefetch" href="/docs/assets/js/87.8a31f5ae.js"><link rel="prefetch" href="/docs/assets/js/88.0f10e6dc.js"><link rel="prefetch" href="/docs/assets/js/89.a17253c9.js"><link rel="prefetch" href="/docs/assets/js/9.2fa568cb.js"><link rel="prefetch" href="/docs/assets/js/90.e56bc609.js"><link rel="prefetch" href="/docs/assets/js/91.5277db18.js"><link rel="prefetch" href="/docs/assets/js/92.b0bb8aa7.js"><link rel="prefetch" href="/docs/assets/js/93.cd790b77.js"><link rel="prefetch" href="/docs/assets/js/94.76bbe227.js"><link rel="prefetch" href="/docs/assets/js/95.4f07ca32.js"><link rel="prefetch" href="/docs/assets/js/96.2b1e8485.js"><link rel="prefetch" href="/docs/assets/js/97.e93b3461.js"><link rel="prefetch" href="/docs/assets/js/98.658063a1.js"><link rel="prefetch" href="/docs/assets/js/99.a3642e6d.js">
    <link rel="stylesheet" href="/docs/assets/css/0.styles.efa081cd.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/docs/" class="home-link router-link-active"><!----> <span class="site-name">Guru Note</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----> <svg aria-hidden="true" class="icon search-icon"><use xlink:href="#icon-search"></use></svg></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/docs/layout/" class="nav-link">
  CSS 手册
</a></div><div class="nav-item"><a href="/docs/js/" class="nav-link">
  JavaScript
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端进阶" class="dropdown-title"><span class="title">前端进阶</span> <span class="arrow down"></span></button> <button type="button" aria-label="前端进阶" class="mobile-dropdown-title"><span class="title">前端进阶</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          前端框架
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/docs/vue/" class="nav-link router-link-active">
  Vue.js
</a></li><li class="dropdown-subitem"><a href="/docs/react/" class="nav-link">
  React.js
</a></li></ul></li><li class="dropdown-item"><h4>
          拓展语言
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/docs/node/" class="nav-link">
  Node.js
</a></li><li class="dropdown-subitem"><a href="/docs/ts/" class="nav-link">
  TypeScript
</a></li></ul></li></ul></div></div><div class="nav-item"><a href="/docs/devbook/" class="nav-link">
  开发手册
</a></div><div class="nav-item"><a href="/docs/exam/" class="nav-link">
  金九银十
</a></div><div class="nav-item"><a href="/docs/message/" class="nav-link">
  留言板
</a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><div class="el-scrollbar"><div class="scrollbar-wrapper el-scrollbar__wrap el-scrollbar__wrap--hidden-default"><div class="el-scrollbar__view"><nav class="nav-links"><div class="nav-item"><a href="/docs/layout/" class="nav-link">
  CSS 手册
</a></div><div class="nav-item"><a href="/docs/js/" class="nav-link">
  JavaScript
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端进阶" class="dropdown-title"><span class="title">前端进阶</span> <span class="arrow down"></span></button> <button type="button" aria-label="前端进阶" class="mobile-dropdown-title"><span class="title">前端进阶</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          前端框架
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/docs/vue/" class="nav-link router-link-active">
  Vue.js
</a></li><li class="dropdown-subitem"><a href="/docs/react/" class="nav-link">
  React.js
</a></li></ul></li><li class="dropdown-item"><h4>
          拓展语言
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/docs/node/" class="nav-link">
  Node.js
</a></li><li class="dropdown-subitem"><a href="/docs/ts/" class="nav-link">
  TypeScript
</a></li></ul></li></ul></div></div><div class="nav-item"><a href="/docs/devbook/" class="nav-link">
  开发手册
</a></div><div class="nav-item"><a href="/docs/exam/" class="nav-link">
  金九银十
</a></div><div class="nav-item"><a href="/docs/message/" class="nav-link">
  留言板
</a></div> <!----></nav>  <ul class="sidebar-links"><li><a href="/docs/vue/" aria-current="page" class="sidebar-link">说明</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Vue 2.0 全解</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/docs/vue/options.html" class="sidebar-link">Vue 简介 &amp; 构造选项</a></li><li><a href="/docs/vue/responsive.html" aria-current="page" class="active sidebar-link">Vue 数据响应式</a></li><li><a href="/docs/vue/computed-and-watch.html" class="sidebar-link">Vue 计算属性和监听器</a></li><li><a href="/docs/vue/template-instruction-modifier.html" class="sidebar-link">Vue 模板、指令与修饰符</a></li><li><a href="/docs/vue/advanced-options.html" class="sidebar-link">Vue 进阶属性</a></li><li><a href="/docs/vue/prop.html" class="sidebar-link">Vue Prop 自定义属性</a></li><li><a href="/docs/vue/form-and-model.html" class="sidebar-link">Vue 表单与输入绑定</a></li><li><a href="/docs/vue/router.html" class="sidebar-link">Vue Router 的原理</a></li><li><a href="/docs/vue/transition.html" class="sidebar-link">Vue 动画原理</a></li><li><a href="/docs/vue/tree-component.html" class="sidebar-link">递归组件</a></li><li><a href="/docs/vue/plugin.html" class="sidebar-link">Vue 常用插件</a></li><li><a href="/docs/vue/create-project.html" class="sidebar-link">Vue 快速搭建项目</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>VuePress</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/docs/vue/vuepress/started.html" class="sidebar-link">快速搭建文档</a></li><li><a href="/docs/vue/vuepress/markdown.html" class="sidebar-link">Markdown 语法拓展</a></li><li><a href="/docs/vue/vuepress/element-ui.html" class="sidebar-link">添加 Element 组件</a></li><li><a href="/docs/vue/vuepress/file-path.html" class="sidebar-link">关于文件路径</a></li></ul></section></li></ul> </div></div><div class="el-scrollbar__bar is-horizontal"><div class="el-scrollbar__thumb" style="width:0;transform:translateX(0%);ms-transform:translateX(0%);webkit-transform:translateX(0%);"></div></div><div class="el-scrollbar__bar is-vertical"><div class="el-scrollbar__thumb" style="height:0;transform:translateY(0%);ms-transform:translateY(0%);webkit-transform:translateY(0%);"></div></div></div></aside> <main class="page"> <div class="re-page-top"><h1 class="title"><span>Vue 数据响应式</span></h1> <div class="re-page-index"><div class="page-index-title"><span class="open-catalog"><svg aria-hidden="true" class="icon arrow-right"><use xlink:href="#icon-bold-right"></use></svg> <span class="text">目录</span></span></div> <div class="page-index-content"><div class="page-catalog" style="display:none;"><div class="synopsis-wrap"><ul class="synopsis-ul"><li class="synopsis-li"><a href="/docs/vue/responsive.html#getter" class="synopsis-link">getter</a></li><li class="synopsis-li"><a href="/docs/vue/responsive.html#setter" class="synopsis-link">setter</a></li><li class="synopsis-li"><a href="/docs/vue/responsive.html#getter-setter" class="synopsis-link">getter + setter</a></li><li class="synopsis-li"><a href="/docs/vue/responsive.html#object-defineproperty" class="synopsis-link">Object.defineProperty()</a></li><li class="synopsis-li"><a href="/docs/vue/responsive.html#object-defineproperty-实现代理" class="synopsis-link">Object.defineProperty 实现代理</a></li><li class="synopsis-li"><a href="/docs/vue/responsive.html#总结" class="synopsis-link">总结</a></li></ul></div></div></div></div></div> <div class="theme-default-content content__default"><p>在理解 Vue 数据响应式之前，首先要理解一些 ES6 之后的新语法，如 <code>getter</code>、<code>setter</code>、<code>Object.defineProperty()</code>。</p> <h2 id="getter"><a href="#getter" class="header-anchor">#</a> getter</h2> <p>可以给对象的属性设置获取时的值，通过函数 return 的方式返回。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">let</span> object <span class="token operator">=</span> <span class="token punctuation">{</span>
  姓<span class="token operator">:</span> <span class="token string">'张'</span><span class="token punctuation">,</span>
  名<span class="token operator">:</span> <span class="token string">'三'</span><span class="token punctuation">,</span>
  <span class="token keyword">get</span> <span class="token function">姓名</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>姓 <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>名
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>object<span class="token punctuation">.</span>姓名<span class="token punctuation">)</span> <span class="token comment">// 张三</span>
</code></pre></div><h2 id="setter"><a href="#setter" class="header-anchor">#</a> setter</h2> <p>可以给对象的属性设置一个修改该属性时所做的操作，依然是一个函数，函数的第一个参数就是修改时赋给该属性的新值。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">let</span> object <span class="token operator">=</span> <span class="token punctuation">{</span>
  姓<span class="token operator">:</span> <span class="token string">'张'</span><span class="token punctuation">,</span>
  名<span class="token operator">:</span> <span class="token string">'三'</span><span class="token punctuation">,</span>
  <span class="token keyword">set</span> <span class="token function">姓名</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>姓 <span class="token operator">=</span> value<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>名 <span class="token operator">=</span> value<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
object<span class="token punctuation">.</span>姓名 <span class="token operator">=</span> <span class="token string">'李四'</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>object<span class="token punctuation">.</span>姓<span class="token punctuation">)</span> <span class="token comment">// 李</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>object<span class="token punctuation">.</span>名<span class="token punctuation">)</span> <span class="token comment">// 四</span>
</code></pre></div><h2 id="getter-setter"><a href="#getter-setter" class="header-anchor">#</a> getter + setter</h2> <p>通常情况下，我们习惯将两个属性结合起来使用，如下：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">let</span> object <span class="token operator">=</span> <span class="token punctuation">{</span>
  姓<span class="token operator">:</span> <span class="token string">'张'</span><span class="token punctuation">,</span>
  名<span class="token operator">:</span> <span class="token string">'三'</span><span class="token punctuation">,</span>
  <span class="token keyword">get</span> <span class="token function">姓名</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>姓 <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>名
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token keyword">set</span> <span class="token function">姓名</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>姓 <span class="token operator">=</span> value<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>名 <span class="token operator">=</span> value<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
object<span class="token punctuation">.</span>姓名 <span class="token operator">=</span> <span class="token string">'王五'</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>object<span class="token punctuation">.</span>姓名<span class="token punctuation">)</span>
</code></pre></div><h2 id="object-defineproperty"><a href="#object-defineproperty" class="header-anchor">#</a> <code>Object.defineProperty()</code></h2> <p>有时候在声明对象后，又想给对象添加一个带有 getter 和 setter 的值。这时候就需要使用 <code>Object.defineProperty()</code></p> <p>它接受三个参数，第一个是要添加的对象，第二个是要添加的对象的属性，第三个是由 getter 和 setter 两个属性组成的对象（注：此处的 getter 和 setter 后不需要再加属性名），示例：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">let</span> object <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'张三'</span> <span class="token punctuation">}</span>
<span class="token keyword">let</span> _email <span class="token operator">=</span> <span class="token string">'123@xx.com'</span>
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>object<span class="token punctuation">,</span> <span class="token string">'email'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> _email
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token function">set</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    _email <span class="token operator">=</span> value
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>object<span class="token punctuation">.</span>email<span class="token punctuation">)</span> <span class="token comment">// 123@xx.com</span>
object<span class="token punctuation">.</span>email <span class="token operator">=</span> <span class="token string">'5885653362@qq.com'</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>object<span class="token punctuation">.</span>email<span class="token punctuation">)</span> <span class="token comment">// 5885653362@qq.com</span>
</code></pre></div><p>上面的代码还有一个缺陷，就是每次都要再次声明一个变量 <code>_email</code> 来存储真实 <code>email</code> 的值，我们可以通过以下的代理函数来解决这个问题。</p> <h2 id="object-defineproperty-实现代理"><a href="#object-defineproperty-实现代理" class="header-anchor">#</a> <code>Object.defineProperty</code> 实现代理</h2> <p><strong>假如要实现一个限制输入的数字不能小于 0 的需求</strong></p> <p>我们可以封装如下函数</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token function">proxy</span><span class="token punctuation">(</span><span class="token punctuation">{</span> data<span class="token operator">:</span> <span class="token punctuation">{</span>n<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// 生成一个匿名对象，外部无法访问</span>
<span class="token comment">// 将 data 解构赋值，传入函数</span>
<span class="token keyword">function</span> <span class="token function">proxy</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>data<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> object <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token comment">// 使用 defineProperty 代理 data 中的每一个属性</span>
  <span class="token comment">// 此处应该是循环遍历对象的每一个属性，为了简化代码暂时省略。</span>
  Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>object<span class="token punctuation">,</span> <span class="token string">'n'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> data<span class="token punctuation">.</span>n
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function">set</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span><span class="token punctuation">(</span>value <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">return</span>
      data<span class="token punctuation">.</span>n <span class="token operator">=</span> value
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span> object
<span class="token punctuation">}</span>

<span class="token comment">// 此时设置 data 的值</span>
data<span class="token punctuation">.</span>n <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>n<span class="token punctuation">)</span> <span class="token comment">// 修改失败，返回 0</span>
data<span class="token punctuation">.</span>n <span class="token operator">=</span> <span class="token number">1</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>n<span class="token punctuation">)</span> <span class="token comment">// 修改成功，返回 1</span>
</code></pre></div><p>但是如果传入一个命名对象，那么还是可以修改 <code>data</code> 的属性为 <code>-1</code>，如下</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">let</span> myData <span class="token operator">=</span> <span class="token punctuation">{</span>n<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">}</span>
<span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token function">proxy</span><span class="token punctuation">(</span><span class="token punctuation">{</span> data<span class="token operator">:</span> myData <span class="token punctuation">}</span><span class="token punctuation">)</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>n<span class="token punctuation">)</span> <span class="token comment">// 0</span>
myData<span class="token punctuation">.</span>n <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>n<span class="token punctuation">)</span> <span class="token comment">// -1</span>
</code></pre></div><p>这时候就要实现一个即使传入命名对象，也可以限制该对象的属性。只要在原有的代码上添加对原对象也使用 <code>Object.defineProperty</code> 代理，该代理会直接覆盖对象的默认属性的 getter 和 setter</p> <div class="language-js extra-class"><div class="highlight-lines"><br><br><br><br><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br></div><pre class="language-js"><code><span class="token keyword">let</span> myData <span class="token operator">=</span> <span class="token punctuation">{</span>n<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">}</span>
<span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token function">proxy</span><span class="token punctuation">(</span><span class="token punctuation">{</span> data<span class="token operator">:</span> myData <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function">proxy</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>data<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> value <span class="token operator">=</span> data<span class="token punctuation">.</span>n
  <span class="token keyword">delete</span> data<span class="token punctuation">.</span>n <span class="token comment">// 此行可以删掉，因为通过 defineProperty 设置属性时会覆盖存在的值</span>
  Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token string">'n'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> value
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function">set</span><span class="token punctuation">(</span>newValue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>newValue <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">return</span>
      value <span class="token operator">=</span> newValue
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

  <span class="token keyword">const</span> object <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>object<span class="token punctuation">,</span> <span class="token string">'n'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> data<span class="token punctuation">.</span>n
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function">set</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>value <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token comment">// 此行可以删掉，因为上面已经做了一次判断进行限制</span>
      data<span class="token punctuation">.</span>n <span class="token operator">=</span> value
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

  <span class="token keyword">return</span> object
<span class="token punctuation">}</span>
</code></pre></div><h2 id="总结"><a href="#总结" class="header-anchor">#</a> 总结</h2> <p>Vue 数据响应式实现的原理，基本上就是 通过 <code>Object.defineProperty</code> 的 <code>getter</code> 和 <code>setter</code> 劫持数据。并拷贝一个数据实现的。</p></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">上次更新：</span><span class="time">2021-02-10 12:44</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev"><svg aria-hidden="true" class="icon"><use xlink:href="#icon-left"></use></svg> <a href="/docs/vue/options.html" class="prev">Vue 简介 &amp; 构造选项</a></span> <span class="next"><a href="/docs/vue/computed-and-watch.html">Vue 计算属性和监听器</a> <svg aria-hidden="true" class="icon"><use xlink:href="#icon-right"></use></svg></span></p></div> </main></div><div class="global-ui"><!----><!----></div></div>
    <script src="/docs/assets/js/app.cdec4db9.js" defer></script><script src="/docs/assets/js/2.993bd611.js" defer></script><script src="/docs/assets/js/119.cbb17c5e.js" defer></script><script src="/docs/assets/js/7.5a12abef.js" defer></script>
  </body>
</html>
